Let's Go by Alex Edwards

Let's Go by Alex Edwards

Author:Alex Edwards
Language: eng
Format: epub


Using the helpers

Alright, let’s start putting the Validator type to use!

We’ll head back to our cmd/web/handlers.go file and update it to embed a Validator instance in our snippetCreateForm struct, and then use this to perform the necessary validation checks on the form data.

Tip: If you’re not familiar with the concept of embedding structs in Go, Eli Bendersky has written a good introduction on the topic and I recommend quickly reading it before you continue.

Like so:

File: cmd/web/handlers.go package main import ( "errors" "fmt" "net/http" "strconv" "snippetbox.alexedwards.net/internal/models" "snippetbox.alexedwards.net/internal/validator" // New import "github.com/julienschmidt/httprouter" ) ... // Remove the explicit FieldErrors struct field and instead embed the Validator // type. Embedding this means that our snippetCreateForm "inherits" all the // fields and methods of our Validator type (including the FieldErrors field). type snippetCreateForm struct { Title string Content string Expires int validator.Validator } func (app *application) snippetCreatePost(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { app.clientError(w, http.StatusBadRequest) return } expires, err := strconv.Atoi(r.PostForm.Get("expires")) if err != nil { app.clientError(w, http.StatusBadRequest) return } form := snippetCreateForm{ Title: r.PostForm.Get("title"), Content: r.PostForm.Get("content"), Expires: expires, // Remove the FieldErrors assignment from here. } // Because the Validator type is embedded by the snippetCreateForm struct, // we can call CheckField() directly on it to execute our validation checks. // CheckField() will add the provided key and error message to the // FieldErrors map if the check does not evaluate to true. For example, in // the first line here we "check that the form.Title field is not blank". In // the second, we "check that the form.Title field has a maximum character // length of 100" and so on. form.CheckField(validator.NotBlank(form.Title), "title", "This field cannot be blank") form.CheckField(validator.MaxChars(form.Title, 100), "title", "This field cannot be more than 100 characters long") form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank") form.CheckField(validator.PermittedInt(form.Expires, 1, 7, 365), "expires", "This field must equal 1, 7 or 365") // Use the Valid() method to see if any of the checks failed. If they did, // then re-render the template passing in the form in the same way as // before. if !form.Valid() { data := app.newTemplateData(r) data.Form = form app.render(w, http.StatusUnprocessableEntity, "create.tmpl", data) return } id, err := app.snippets.Insert(form.Title, form.Content, form.Expires) if err != nil { app.serverError(w, err) return } http.Redirect(w, r, fmt.Sprintf("/snippet/view/%d", id), http.StatusSeeOther) }

So this is shaping up really nicely.

We’ve now got an internal/validator package with validation rules and logic that can be reused across our application, and it can easily be extended to include additional rules in the future. Both form data and errors are neatly encapsulated in a single snippetCreateForm struct — which we can easily pass to our templates — and the API for displaying error messages and re-populating the data in our templates is simple and consistent.

If you like, go ahead and re-run the application now. All being well, you should find that the form and validation rules are working correctly and in exactly the same manner as before.



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.